 <?php
	

use \GatewayWorker\Lib\Gateway;

include_once(dirname(__DIR__) .'/Module/Verification.class.php');
include_once(dirname(__DIR__) .'/Module/Socket.class.php');
include_once(dirname(__DIR__) .'/Module/Redis.class.php');
require_once dirname(__DIR__) . '/base.class.model.php';
require_once __DIR__ . '/Landlord.php';
class Public_Model extends Base_Model
{

	//扣除房卡或退还房卡
	protected function balanceTicket($room_id, $account_id, $spend_ticket_count){
		$timestamp = time();
		$MMYSQL = $this->initMysql();
		$MMYSQL->update(Room_Ticket)->set("ticket_count", "ticket_count-".$spend_ticket_count)->where("account_id=".$account_id)->query();

		//获取流水账
		$balance = 0;
		$balance_where = 'account_id='.$account_id.' and is_delete=0';
		$balance_sql = 'select balance from '.Room_Ticket_Journal.' where '.$balance_where.' order by journal_id desc';

		$balance_query = $MMYSQL->query($balance_sql);
		if(is_array($balance_query) && count($balance_query) > 0 ){
			$balance = $balance_query[0]['balance'];
		}

		//添加到流水账
		$journal_array['create_time'] = $timestamp;
		$journal_array['create_appid'] = "aid_".$account_id;
		$journal_array['update_time'] = $timestamp;
		$journal_array['update_appid'] = "aid_".$account_id;
		$journal_array['is_delete'] = G_CONST::IS_FALSE;
		$journal_array['account_id'] = $account_id;
		$journal_array['object_id'] = $room_id;
		$journal_array['object_type'] = 3;  //游戏

		$journal_array['extra'] = "";

		if($spend_ticket_count > 0){
			$journal_array['disburse'] = $spend_ticket_count;
			$journal_array['abstract'] = "斗地主";		//摘要
		} else {
			$journal_array['income'] = -$spend_ticket_count;
			$journal_array['abstract'] = "斗地主房卡退还";		//摘要
		}

		$journal_array['balance'] = $balance - $spend_ticket_count;
		if($journal_array['balance'] < 0)
		{
			$this->writeLog("balance negative balance: ".$balance." account_id: ".$account_id." room_id: ".$room_id);
			$journal_array['balance'] = 0;
		}
		$journal_id = $MMYSQL->insertReturnID(Room_Ticket_Journal,$journal_array);
	}


	//获取房间玩法设置
	protected function queryRoomSetting($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetallField($Room_Key);
		return $result;
	}

	//获取当前桌面牌的用户id
	protected function queryCurrentCardUser($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_CurrentUser);
		return $result > 0 ? $result : -1;
	}

	//上家出牌
	public function queryCurrentCard($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$CurrentCard_Key = strtr(Redis_Const::CurrentCard_Key, $replyArr);

		$list = $Redis_Model->lrangeList($CurrentCard_Key,0,-1); 
		if($list){
			return $list;
		} else {
			return array();
		}
	}
	public function updateCurrentCard($room_id, $account_id, $card){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);

		$CurrentCard_Key = strtr(Redis_Const::CurrentCard_Key, $replyArr);

		//先清空队列
		$Redis_Model->deleteKey($CurrentCard_Key);	
		//再入队
		$result = $Redis_Model->pushList(1,0,$CurrentCard_Key, $card);

		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$mkv[Redis_Const::Play_Field_CurrentUser] = $account_id;
		$result = $Redis_Model->hmsetField($Play_Key, $mkv );

		return $result;
	}

	public function queryLandlordCard($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$LandlordCard_Key = strtr(Redis_Const::LandlordCard_Key, $replyArr);

		$list = $Redis_Model->lrangeList($LandlordCard_Key,0,-1); 
		if($list){
			return $list;
		} else {
			return array();
		}
	}
	public function setLandlordCard($room_id, $card){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$LandlordCard_Key = strtr(Redis_Const::LandlordCard_Key, $replyArr);

		$result = $Redis_Model->pushList(1,0,$LandlordCard_Key, $card);
		return $result;
	}
	public function queryPlayerCard($room_id, $account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3])){
			$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;
			$list = $Redis_Model->lrangeList($PlayerCard_Key,0,-1); 
			if($list){
				return $list;
			} else {
				return array();
			}
		} else {
			return -2;
		}
	}
	public function queryPlayerCardCount($room_id, $account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3])){
			$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;
			$len = $Redis_Model->llenList($PlayerCard_Key); 
			return $len;
		} else {
			return -2;
		}
	}

	public function setPlayerCard($room_id, $account_id, $card){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3])){
			$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;

			//先清空队列
			$Redis_Model->deleteKey($PlayerCard_Key);	
			//再入队
			$result = $Redis_Model->pushList(1,0,$PlayerCard_Key, $card);


			//显示手牌
			$my_card = $this->queryPlayerCard($room_id, $account_id);
			$msg_arr = array(
				'result' => 0,
				'operation' => 'MyCard',
				'result_message' => "我的手牌",
				'data' => array(
					'my_card' => $my_card,
					)
				);
			$this->pushMessageToAccount($room_id, $account_id, $msg_arr);

			return $result;
		} else {
			return OPT_CONST::FAILED;
		}

	}
	public function removePlayerCard($room_id, $account_id, $cards){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $account_id);
		if(in_array($seat_number, [1,2,3])){
			$PlayerCard_Key = "PlayerCard:".$seat_number.":".$room_id;

			if(is_array($cards)){
				$result = 0;
				foreach ($cards as $acard) {
					$result += $Redis_Model->lremList($PlayerCard_Key, 0, $acard);
				}
			} else {
				$result = $Redis_Model->lremList($PlayerCard_Key, 0, $cards);
			}
			return $result;
		} else {
			return OPT_CONST::FAILED;
		}
	}


	protected function setHashTransaction($room_id)
	{
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$key = strtr(Redis_Const::Room_Key, $replyArr);

		$redisAuth = $Redis_Model->pingRedisAuth();
		if($redisAuth === G_CONST::EMPTY_STRING || !is_object($redisAuth))
		{
			$this->logMessage('error', "function(existsKey):redisAuth is empty string"." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

	    $success = false;
	    $options = array(
	        'cas'   => true,    // Initialize with support for CAS operations
	        'watch' => $key,    // Key that needs to be WATCHed to detect changes
	        'retry' => 3,       // Number of retries on aborted transactions, after
	                            // which the client bails out with an exception.
	    );

	    $redisAuth->transaction($options, function ($tx) use ($key, &$success) {
	        $room_status = $tx->hget($key, Redis_Const::Room_Field_Status);
	        if (isset($room_status) && $room_status == 1) {
	            $tx->multi();   // With CAS, MULTI *must* be explicitly invoked.
	            $tx->hmset($key, array(Redis_Const::Room_Field_Status => 2));
	            $success =  true;

	        } else {
	        	$this->writeLog("room_status != 1");
	        	$success =  false;
	        }
	    });
	    return $success;
	}

	//开局
	protected function startGame($room_id)
	{
		$timestamp = time();
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		

		$ready_user = $this->queryReadyUser($room_id);
		$in_room_array = $this->queryInRoomUser($room_id);
		$ready_count = count($ready_user);
		$online_count = count($in_room_array);
			
		$this->writeLog("[$room_id] 准备:".$ready_count."人  "."在线:".$online_count."人");

		if($ready_count >=3)
		{
			if($ready_count == $online_count){


				$room_members = $this->queryRoomMembers($room_id);

				$readyUser_ary = array();
				foreach($room_members as $account_id)
				{
					$ready_count ++;
					$readyUser_ary[] = $account_id;
				}

				$success = $this->setHashTransaction($room_id);
				if(!$success){
					$this->writeLog("并发 start game，忽略。room id:".$room_id."。in file".__FILE__." on Line ".__LINE__);
					return false;
				}

				if(Config::Room_AutoBreak){
					//取消倒计时(自动解散房间定时器)
					$this->deleteRoomTimer($room_id);
				}

				//开始游戏
				//扣房卡
				$ticket_checked_user = $this->queryTicketCheckedUser($room_id);
				$to_check_user_array = array_diff($readyUser_ary, $ticket_checked_user);
				if(count($to_check_user_array) > 0){

					$setting = $this->queryRoomSetting($room_id);
					$spend_ticket_count=isset($setting[Redis_Const::Room_Field_TicketCount]) ?$setting[Redis_Const::Room_Field_TicketCount]:1;

					foreach ($to_check_user_array as $account_id) {
						
						if(Config::Ticket_Mode == 1){
							//扣除房卡
							$this->balanceTicket($room_id, $account_id, $spend_ticket_count);
						}
						$mkv[$account_id] = 1;
					}

					$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);
					$Redis_Model->hmsetField($TicketChecked_Key,$mkv);
				}


				//房间轮数与局数更新
				$this->updateGameNumberRound($room_id);

				$this->initGame($room_id, $readyUser_ary);

			} 
		}
		
		return true;
	}

	//开局
	protected function initGame($room_id, $readyUser_ary=array())
	{
		$gnum = $this->queryGameNumber($room_id);
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		
		//设置每局玩家顺序list
		$setting = $this->queryRoomSetting($room_id);
		$ask_mode=isset($setting[Redis_Const::Room_Field_AskMode]) ?$setting[Redis_Const::Room_Field_AskMode]:2;

		if($ask_mode == 2){
			$offset = mt_rand(0,2);
		} else {
			$creator = $this->queryCreator($room_id);
			if($creator > 0){
				$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
				$seat_number = $Redis_Model->getZscore($RoomSequence_Key, $creator);
				$offset = ($seat_number + $gnum - 2) % 3;
			} else {
				$offset = ($gnum - 1) % 3;
			}
		}

		$play_member = array_merge(array_slice($readyUser_ary, $offset), array_slice($readyUser_ary,0,$offset));
		$next_banker_id = $play_member[0];

		//开始游戏				
		$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);

		$LandlordCard_Key = strtr(Redis_Const::LandlordCard_Key, $replyArr);
		$CurrentCard_Key = strtr(Redis_Const::CurrentCard_Key, $replyArr);

		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);	//本局输赢
		
		//删除每局玩家手牌hash
		for ($i=1; $i <= 3; $i++) { 
			$Redis_Model->deleteKey("PlayerCard:".$i.":".$room_id);
		}
		$Redis_Model->deleteKey($LandlordCard_Key);
		$Redis_Model->deleteKey($CurrentCard_Key);
		$Redis_Model->deleteKey($Chip_Key);
		
		//删除每局玩家顺序list
		$Redis_Model->deleteKey($PlayMember_Key);
		
		$AccountStatus_mvk = array();

		$readyUserCount = count($play_member);  //游戏中玩家数量

		$Chip_mvk = array();
		$landlord = Landlord::instance();
		$player_cards = $landlord->dealCard();  //发牌
		
		for ($i=0; $i < $readyUserCount; $i++) 
		{
			$account_id = $play_member[$i];
			$AccountStatus_mvk[$account_id] = Game::AccountStatus_NotAsk;
			$Chip_mvk[$account_id] = 0;
		
			//设置每局玩家手牌
			$this->setPlayerCard($room_id, $account_id, $player_cards[$i]);
		}

		$Redis_Model->hmsetField($Chip_Key,$Chip_mvk);
		//设置地主牌
		$this->setLandlordCard($room_id, $player_cards[3]);


		$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$AccountStatus_mvk);
		$push_result = $Redis_Model->pushList($is_rpush=0,$is_pushx=0,$PlayMember_Key,$play_member); //lpush
		
		//重设每局游戏参数
		$parameter_ary[Redis_CONST::Play_Field_Multiple] = 1;  //当前倍数
		$parameter_ary[Redis_CONST::Play_Field_Landlord] = -1;	//地主
		$parameter_ary[Redis_CONST::Play_Field_CurrentUser] = -1;  //当前牌的用户
		$parameter_ary[Redis_CONST::Play_Field_NotPassCount] = 0;  //地主出牌次数
		$parameter_ary[Redis_CONST::Play_Field_FarmerNotPassCount] = 0;  //农民出牌次数
		$parameter_ary[Redis_CONST::Play_Field_ActiveUser] =  $next_banker_id;	//当前操作用户, 从庄家开始
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$mset_result = $Redis_Model->hmsetField($Play_Key,$parameter_ary);

		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$Room_mkv[Redis_CONST::Room_Field_Status] = 2;  //房间状态，1等待、2进行中、3关闭
		$mset_result = $Redis_Model->hmsetField($Room_Key,$Room_mkv);

		$player_status = array();
		foreach ($play_member as $player_id) {
			if($player_id == $next_banker_id){
				$player_status[] = array(
						"account_id"=> $player_id,
				        "account_status"=> Game::AccountStatus_NotAsk,		 //5; 持牌
				        "online_status" => $this->queryOnlineStatus($room_id, $player_id),
				        "playing_status"=> Game::PlayingStatus_Asking, //2;  叫地主
				        "limit_time" => Game::LimitTime_Asking,
					);
			} else {
				$player_status[] = array(
						"account_id"=> $player_id,
				        "account_status"=> Game::AccountStatus_NotAsk,		 //5; 持牌
				        "online_status" => $this->queryOnlineStatus($room_id, $player_id),
				        "playing_status"=> Game::PlayingStatus_Waiting, //1 等待别人中
				        "limit_time" => 0
					);
			}
		}
		//设置自动叫地主定时器
		$this->setupAskLandlordPassiveTimer($room_id, $next_banker_id);

		//推送开始
		
		$arr = array("result"=>0,"operation"=>"GameStart","data"=>array('player_status'=>$player_status, 'game_num'=>$gnum),"result_message"=>"游戏开始了");
		$this->pushMessageToGroup($room_id, $arr);
		
		return true;
	}


	//设置 自动出牌 定时器
	protected function setupChooseCardPassiveTimer($room_id, $account_id){

		$callback_array = array(
			'operation' => "ChooseCardPassive",
			'room_id' => $room_id,
			'data' => array(
				'account_id' => $account_id
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_Choosing,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//设置 自动叫地主 定时器
	protected function setupAskLandlordPassiveTimer($room_id, $account_id){

		$callback_array = array(
			'operation' => "AskLandlordPassive",
			'room_id' => $room_id,
			'data' => array(
				'account_id' => $account_id
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_Choosing,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//设置 清理房间 定时器
	protected function setupClearRoomPassiveTimer($room_id){

		$this->writeLog("[$room_id] 设置了自动清扫房间定时器");
		$callback_array = array(
			'operation' => "ClearRoomPassive",
			'room_id' => $room_id,
			'data' => array(
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_ClearRoom,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//设置 解散房间 定时器
	protected function setupBreakRoomPassiveTimer($room_id){

		$this->writeLog("[$room_id] 设置了自动解散房间定时器");
		$callback_array = array(
			'operation' => "BreakRoomPassive",
			'room_id' => $room_id,
			'data' => array(
				)
			);
		$arr = array(
			'operation' => "BuildTimer",
			'room_id'   => $room_id,
			'data' => array(
				'limit_time' => Game::LimitTime_BreakRoom,
				'callback_array' => $callback_array
				)
			);
		$this->sendToTimerServer($arr);
	}

	//删除定时器
	protected function deleteRoomTimer($room_id){

		$timer_id = $this->queryTimerId($room_id);
		if($timer_id > 0){
			$arr = array(
				'operation' => "DeleteTimer",
				'room_id'   => $room_id,
				'data' => array(
					'timer_id' => $timer_id
					)

				);
			$this->sendToTimerServer($arr);
		}
		$this->updateTimer($room_id, -1);
	}


	//查询倒计时
	protected function queryCountdown($room_id, $limit){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$timer_time = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_TimerTime);

		if($timer_time > 0){
			$countdown = $limit - time() + $timer_time;
			return $countdown > 0 ? $countdown : 0;
		} else {
			return 0;
		}
	}

	//设置或取消(timer_id  -1)定时器
	protected function updateTimer($room_id, $timer_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$mkv[Redis_Const::Play_Field_TimerId] = $timer_id;
		if($timer_id > 0){
			$mkv[Redis_Const::Play_Field_TimerTime] = time();
		} else {
			$mkv[Redis_Const::Play_Field_TimerTime] = -1;
		}

		$mset_result = $Redis_Model->hmsetField($Play_Key,$mkv);
	}

	//获取定时器id
	protected function queryTimerId($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_TimerId);
		return $result > 0 ? $result : -1;
	}

	//更新房间状态
	protected function updateRoomStatus($room_id, $status){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$mkv[Redis_Const::Room_Field_Status] = $status;
		$mset_result = $Redis_Model->hmsetField($Room_Key,$mkv);
	}

	//重新设置所有用户状态为未准备
	protected function resetAllAccountStatus($room_id, $reset_status=Game::AccountStatus_Notready){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);

		$mkv = array();
		$members = $this->queryRoomMembers($room_id);
		if(is_array($members) && count($members)){
			foreach ($members as $account_id) {
				$pre_status = $this->queryAccountStatus($room_id, $account_id);
				$status = ($pre_status == Game::AccountStatus_Initial) ? Game::AccountStatus_Initial : $reset_status;

				$mkv[$account_id] = $status;
			}
		}
		$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$mkv);  //用户状态
	}

	//重新设置所有用户分数为0
	protected function resetAllAccountScore($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);

		$mkv = array();
		$members = $this->queryRoomMembers($room_id);
		if(is_array($members) && count($members)){
			foreach ($members as $account_id) {
				$mkv[$account_id] = 0;
			}
		}
		$mset_result = $Redis_Model->hmsetField($RoomScore_Key,$mkv);  //用户状态
	}

	//获取房间用户有序集合
	protected function queryRoomMembers($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$zrange_array['is_zrange'] = true;
		$zrange_array['key'] = $RoomSequence_Key;
		$zrange_array['start'] = 0;
		$zrange_array['stop'] = -1;
		$members = $Redis_Model->zrangeSet($zrange_array);
		// if(is_array($members) && count($members)){
		// 	foreach ($members as $account_id) {
		// 		# code...
		// 	}
		// }
		if(is_array($members)){
			return $members;
		} else {
			return array();
		}
		
	}

	//获取房间状态
	protected function queryRoomStatus($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Status);
		return $result;
	}

	//获取房间每轮需要消耗的房卡数
	protected function queryTicketCount($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_TicketCount);
		return $result > 0 ? $result : 1;
	}

	//获取房间一轮总局数
	protected function queryTotalNum($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_TotalNum);
		return $result;
	}

	//获取房间当前局数
	protected function queryGameNumber($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_GameNum);
		return $result;
	}

	//自增长房间当前局数、轮数
	protected function updateGameNumberRound($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$game_num = $Redis_Model->hincrbyField($Room_Key, Redis_Const::Room_Field_GameNum, 1);
		$this->writeLog("[$room_id] 新的一局 :".$game_num);

		if($game_num == 1){
			//设置开局时间
			$this->updateStartTime($room_id);
		}
	}

	//更新用户状态
	protected function updateAccountStatus($room_id, $account_id, $status){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$mkv[$account_id] = $status;
		$mset_result = $Redis_Model->hmsetField($AccountStatus_Key,$mkv);

		//广播用户状态改变
		$noty_arr = array(
			'account_id' => $account_id,
			'account_status'=>$status,
			'online_status'=>$this->queryOnlineStatus($room_id, $account_id)
			);
		$this->writeLog("[$room_id] ($account_id) 状态改变 ". $status);
		$this->notyUpdateAccountStatusToGroup($room_id, $noty_arr);
	}

	//获取在线状态
	protected function queryOnlineStatus($room_id, $account_id){
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$RoomUser_UID = strtr(Game::RoomUser_UID, $replyArr);

		return Gateway::isUidOnline($RoomUser_UID);
	}


	//获取准备人数
	protected function queryReadyCount($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$result = $Redis_Model->hgetallField($AccountStatus_Key);
		$count = 0;
		if(Redis_CONST::DATA_NONEXISTENT !== $result){
			foreach ($result as $account_id => $status) {
				if($status == Game::AccountStatus_Ready){
					$count++;
				}
			}
		}
		return $count;
	}

	//获取准备的人
	protected function queryReadyUser($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$ready_user_array = [];
		$result = $Redis_Model->hgetallField($AccountStatus_Key);
		if(Redis_CONST::DATA_NONEXISTENT !== $result){
			foreach ($result as $account_id => $status) {
				if($status == Game::AccountStatus_Ready){
					$ready_user_array[] = $account_id;
				}
			}
		}
		return $ready_user_array;
	}
	//获取在房的人
	protected function queryInRoomUser($room_id){
		$in_room_user_array = [];
		$room_members = $this->queryRoomMembers($room_id);

		foreach ($room_members as $account_id) {
			if($this->queryOnlineStatus($room_id, $account_id)){
				$in_room_user_array[] = $account_id;
			}
		}
		return $in_room_user_array;
	}
	//获取扣除了房卡的人
	protected function queryTicketCheckedUser($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);
		
		$user_array = [];
		$result = $Redis_Model->hgetallField($TicketChecked_Key);
		if(Redis_CONST::DATA_NONEXISTENT !== $result){
			foreach ($result as $account_id => $status) {
				if($status == 1){
					$user_array[] = $account_id;
				}
			}
		}
		return $user_array;
	}

	//获取用户是否已经扣除房卡
	protected function queryTicketChecked($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);
		$result = $Redis_Model->hgetField($TicketChecked_Key,$account_id);
		return $result == 1 ? 1 : 0;
	}


	//获取用户状态
	protected function queryAccountStatus($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($AccountStatus_Key,$account_id);
		return $result;
	}

	//获取用户积分
	protected function queryAccountScore($room_id, $account_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($RoomScore_Key,$account_id);
		return $result;
	}

	//返回积分榜
	protected function queryScoreboard($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Scoreboard);
		if($result !== Redis_Const::DATA_NONEXISTENT){
			$arr = json_decode($result);
		} else {
			$arr = new stdClass();
		}
		return $arr;
	}

	//返回上局输赢统计榜
	protected function queryScoreSummary($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);

		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);
		$result = $Redis_Model->hgetallField($Chip_Key);	//每局输赢
		
		if($result !== Redis_Const::DATA_NONEXISTENT){
			return $result;
		} else {
			$result = new stdClass();
		}
		return $result;
	}

	//获取当前倍数
	protected function queryMultiple($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_Multiple);
		return $result > 0 ? $result : 1;
	}

	//当前倍数 * 2
	protected function doubleMultiple($room_id){

		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		
		$multiple = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_Multiple);
		if($multiple > 0){
			$multiple *= 2;
		} else {
			$multiple = 1;
		}
		$mkv[Redis_Const::Play_Field_Multiple] = $multiple;
		$mset_result = $Redis_Model->hmsetField($Play_Key,$mkv);

		$msg_arr = array("result"=>"0","operation"=>"UpdateMultiple","data"=>array('multiple'=>$multiple),"result_message"=>"翻倍");
		$this->pushMessageToGroup($room_id, $msg_arr);

		$this->writeLog("[$room_id] 翻倍 至: ".$multiple."倍");
		return $multiple;
	}

	//获取地主id
	protected function queryLandlord($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_Landlord);
		return $result > 0 ? $result : -1;
	}

	//是否春天
	protected function isSpring($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$landlord_not_pass_cnt = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_NotPassCount);
		$farmer_not_pass_cnt = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_FarmerNotPassCount);

		if($landlord_not_pass_cnt == 1 || $farmer_not_pass_cnt == 0){
			return 1;
		} else {
			return 0;
		}
	}

	//增加地主出牌次数
	protected function increaseNotPassCount($room_id, $is_landlord=true){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);

		if($is_landlord){
			$field = Redis_Const::Play_Field_NotPassCount;
		} else {
			$field = Redis_Const::Play_Field_FarmerNotPassCount;
		}
		$result = $Redis_Model->hincrbyField($Play_Key, $field, 1);
		return $result;
	}

	//获取房主id
	protected function queryCreator($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_Creator);
		return $result;
	}

	//获取激活的操作中的用户
	protected function queryActiveUser($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$result = $Redis_Model->hgetField($Play_Key,Redis_Const::Play_Field_ActiveUser);
		return  $result > 0 ? $result : -1;
	}

	//获取开局时间
	protected function queryStartTime($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		$result = $Redis_Model->hgetField($Room_Key,Redis_Const::Room_Field_StartTime);
		return  $result > 0 ? $result : -1;
	}
	//更新游戏开局时间
	protected function updateStartTime($room_id)
	{
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
		
		$mkv[Redis_Const::Room_Field_StartTime] = time();
		$mset_result = $Redis_Model->hmsetField($Room_Key,$mkv);
		return $mset_result;
	}

	//轮流
	protected function takeTurns($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);
		$result = $Redis_Model->rotationList($PlayMember_Key);

		$list = $Redis_Model->lrangeList($PlayMember_Key,-1,-1);  //队列最右边是当前操作用户
		if($list){
			$account_id = $list[0];
		} else {
			$account_id = -1;
		}

		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$mkv[Redis_Const::Play_Field_ActiveUser] = $account_id;

		$mset_result = $Redis_Model->hmsetField($Play_Key,$mkv);

		return $account_id;
	}

	//获取游戏中的人数
	protected function queryPlayMemberCount($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);
		$result = $Redis_Model->llenList($PlayMember_Key);
		return $result;
	}

	//从游戏中队列踢出
	protected function removeFromPlayMember($room_id, $account_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);

		$Redis_Model->lremList($PlayMember_Key, 0, $account_id);

		$list = $Redis_Model->lrangeList($PlayMember_Key,-1,-1);  //队列最右边是当前操作用户
		if($list){
			$active_id = $list[0];
		} else {
			$active_id = -1;
		}
		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$mkv[Redis_Const::Play_Field_ActiveUser] = $active_id;
		$mset_result = $Redis_Model->hmsetField($Play_Key,$mkv);

		return $active_id;
	}

	//推消息
	protected function pushMessageToGroup($room_id, $msg_arr, $exclude_client_id=null){
		$msg = $this->_JSON($msg_arr);
		Gateway::sendToGroup($room_id, $msg, $exclude_client_id);
	}
	protected function pushMessageToAccount($room_id, $account_id, $msg_arr){
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$RoomUser_UID = strtr(Game::RoomUser_UID, $replyArr);
		$msg = $this->_JSON($msg_arr);
		Gateway::sendToUid($RoomUser_UID, $msg);
	}
	protected function pushMessageToCurrentClient($msg_arr){
		$msg = $this->_JSON($msg_arr);
		Gateway::sendToCurrentClient($msg);
	}

	//广播用户状态改变
	protected function notyUpdateAccountStatusToGroup($room_id, $noty_arr, $exclude_client_id=null){

		if(!isset($noty_arr['account_id']) || !isset($noty_arr['account_status']) ){
			$this->writeLog("function(notyUpdateAccountStatusToGroup):lack of params"." in file".__FILE__." on Line ".__LINE__);
			return false;
		}

		$msg_arr = array("result"=>"0","operation"=>"UpdateAccountStatus","data"=>$noty_arr,"result_message"=>"用户状态改变");
		$this->pushMessageToGroup($room_id, $msg_arr, $exclude_client_id=null);
	}

	//通知用户出牌
	protected function notyUserToChoose($room_id, $account_id){

		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);

		//$this->writeLog("轮到用户".$account_id. "出牌");
		//设置自动出牌定时器
		$this->setupChooseCardPassiveTimer($room_id, $account_id);

		$currentCard = $this->queryCurrentCard($room_id);
		$myCards = $this->queryPlayerCard($room_id, $account_id);
		$landlord = Landlord::instance();
		$tips = $landlord->chooseCard($currentCard,$myCards);
		$noty_arr = array(
			'account_id' => $account_id,
			'playing_status' => Game::PlayingStatus_Choosing,
			'limit_time'	 => Game::LimitTime_Choosing,
			'tips' => $tips
			);
		$msg_arr = array("result"=>"0","operation"=>"NotyChooseCard","data"=>$noty_arr,"result_message"=>"通知出牌");
		$this->pushMessageToAccount($room_id, $account_id, $msg_arr);	//有提示
		$msg_arr['data']['tips'] = array(); //清空提示

		$RoomUser_UID = strtr(Game::RoomUser_UID, $replyArr);
		$exclude_client_id = Gateway::getClientIdByUid($RoomUser_UID);
		$this->pushMessageToGroup($room_id, $msg_arr, $exclude_client_id); //非出牌人，提示为空
	}
	//通知用户叫地主
	protected function notyUserToAsk($room_id, $account_id){

		//设置自动叫地主定时器
		$this->setupAskLandlordPassiveTimer($room_id, $account_id);

		$noty_arr = array(
			'account_id' => $account_id,
			'playing_status' => Game::PlayingStatus_Asking,
			'limit_time'	 => Game::LimitTime_Asking,
			);
		$msg_arr = array("result"=>"0","operation"=>"NotyAskLandlord","data"=>$noty_arr,"result_message"=>"通知叫地主");
		$this->pushMessageToGroup($room_id, $msg_arr);
	}


	//打完牌显示结果
	public function showWin($room_id){
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);
		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);

		$winner_id = $this->queryCurrentCardUser($room_id);

		$players = array();
		$player_cards = array();
		$landlord = $this->queryLandlord($room_id);
		$room_members = $this->queryRoomMembers($room_id);
		foreach ($room_members as $mem_id) {
			if($mem_id == $landlord){
				$players['landlord'][] = $mem_id;
			} else {
				$players['farmers'][] = $mem_id;  
			}
			//手牌
			$cards = $this->queryPlayerCard($room_id, $mem_id);
			$player_cards[] = array(
				'account_id'=> $mem_id,
				'cards' => $cards
				); 
		}

		$spring = $this->isSpring($room_id);
		if($spring){	//地主出牌次数为1，即系春天，翻倍
			$this->doubleMultiple($room_id);
		}

		$multiple = $this->queryMultiple($room_id);
		$setting = $this->queryRoomSetting($room_id);
		$base_score=isset($setting[Redis_Const::Room_Field_BaseScore]) ?$setting[Redis_Const::Room_Field_BaseScore]: Game::Default_Score;

		$score = $base_score * $multiple;
		if($winner_id == $landlord){	//地主赢
			$winner = $players['landlord'];
			$winScore = $score;
		} else {	//农民赢
			$winner = $players['farmers'];
			$winScore = -$score;
		}

		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);
		foreach ($room_members as $mem_id) {
			if($mem_id == $landlord){
				$Redis_Model->hincrbyField($RoomScore_Key, $mem_id, $winScore * 2 );
				$Redis_Model->hincrbyField($Chip_Key, $mem_id, $winScore * 2 );
			} else {
				$Redis_Model->hincrbyField($RoomScore_Key, $mem_id,  -$winScore );
				$Redis_Model->hincrbyField($Chip_Key, $mem_id, -$winScore );
			}
		}

		$scoreboard = $Redis_Model->hgetallField($RoomScore_Key);

		//保存积分榜
		if(is_array($scoreboard)){
			$ticket_checked_user = $this->queryTicketCheckedUser($room_id);
			foreach ($scoreboard as $key => $value) {
				if(!in_array($key, $ticket_checked_user)){
					//未扣房卡的用户不显示在积分榜上
					unset($scoreboard[$key]);
				}
			}
			$board_json_str = json_encode($scoreboard);

		} else {
			$scoreboard = array();
			$board_json_str = "";
		}
		$mkv[Redis_Const::Room_Field_Scoreboard] = $board_json_str;
		$Redis_Model->hmsetField($Room_Key,$mkv);

		$score_summary = $Redis_Model->hgetallField($Chip_Key);	//每局输赢

		$start_time = $this->queryStartTime($room_id);
		$game_num = $this->queryGameNumber($room_id);
		$total_num = $this->queryTotalNum($room_id);
		$msg_arr = array(
			'result' => 0,
			'operation' => 'Win',
			'result_message' => "获胜+积分榜",
			'data' => array(
				'player_cards' => $player_cards,
				'winner' => $winner,
				'score'  => $score,
				'score_board' => $scoreboard,
				'score_summary' => $score_summary,
				'game_num' => $game_num,
				'total_num' =>  $total_num,
				'spring' => $spring
				)
			);
		$this->pushMessageToGroup($room_id, $msg_arr);

		//保存当局游戏结果
		$setting = $this->queryRoomSetting($room_id);
		$round = $setting[Redis_Const::Room_Field_GameRound];

		$game_info['room_id'] = $room_id;
		$game_info['game_type'] = Game::Game_Type;
		$game_info['dealer_num'] = Config::Dealer_Num;
		$game_info['round'] = $round;
		$game_info['game_num'] = $game_num;
		$game_info['total_num'] = $total_num;
		$game_info['extra'] = "";
		//@$this->saveGameResult($game_info);

		$this->updateRoomStatus($room_id, 1);   //房间状态，1等待、2进行中、3关闭
		if($game_num == $total_num){  //最后一局

			$MMYSQL = $this->initMysql();
			
			$round = $Redis_Model->hincrbyField($Room_Key, Redis_Const::Room_Field_GameRound, 1);
			$this->writeLog("[$room_id] 第".($round-1)."轮 结束!");

			$name_board = array();
			foreach ($scoreboard as $account_id => $score) {
				$account_sql = 'select nickname from '.WX_Account.' where account_id ='.$account_id;
				$name = $MMYSQL->single($account_sql);
				$name_board[] = array('name'=>$name, 'score'=>$score, 'account_id'=>$account_id);
				
			}
			//规则文本
			$rule_text = $this->formatRuleText($room_id);
			$balance_scoreboard = array('time'=>time(), 'scoreboard'=>$name_board,'game_num'=>$game_num);
			$balance_board_json_str = json_encode($balance_scoreboard['scoreboard']);

			//保存积分榜
			$board_array['start_time'] = $start_time;
			$board_array['create_time'] = time();
			$board_array['is_delete'] = G_CONST::IS_FALSE;
			$board_array['game_type'] = 2;  //游戏2 斗地主
			$board_array['room_id'] = $room_id;
			$board_array['round'] = $round-1;
			$board_array['game_num'] = $game_num;

			$board_array['rule_text'] = $rule_text;
			$board_array['board'] = $board_json_str;
			$board_array['balance_board'] = $balance_board_json_str;
			$board_id = $MMYSQL->insertReturnID(Room_Scoreboard,$board_array);

			//保存用户积分
			$game_info['score_board'] = $scoreboard;
			$this->saveAccountGameScore($game_info);

			//清理房间
			$this->clearRoom($room_id);

		} else {
			$this->resetAllAccountStatus($room_id);  //重设所有用户状态为未准备

			$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
			$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);
			$LandlordCard_Key = strtr(Redis_Const::LandlordCard_Key, $replyArr);
			$CurrentCard_Key = strtr(Redis_Const::CurrentCard_Key, $replyArr);
			//删除每局游戏参数
			$Redis_Model->deleteKey($Play_Key);
			$Redis_Model->deleteKey($PlayMember_Key);
			$Redis_Model->deleteKey($LandlordCard_Key);
			$Redis_Model->deleteKey($CurrentCard_Key);
			for ($i=1; $i <= 3; $i++) { 
				$PlayerCard_Key = "PlayerCard:".$i.":".$room_id;
				$Redis_Model->deleteKey($PlayerCard_Key);
			}

			if(Config::Room_AutoBreak){
				//3分钟未开局则解散
				$this->setupBreakRoomPassiveTimer($room_id);
			}
		}
	}

	protected function clearRoom($room_id){
		//清理房间
		$Redis_Model = Redis_Model::getModelObject();
		$replyArr = array("[roomid]"=>$room_id);

		$Room_Key = strtr(Redis_Const::Room_Key, $replyArr);
        $newRoomNumber = $Redis_Model->hgetField($Room_Key,Redis_CONST::Room_Field_NewNumber);

		$RoomSequence_Key = strtr(Redis_Const::RoomSequence_Key, $replyArr);
		$RoomScore_Key = strtr(Redis_Const::RoomScore_Key, $replyArr);
		$AccountStatus_Key = strtr(Redis_Const::AccountStatus_Key, $replyArr);
		$TicketChecked_Key = strtr(Redis_Const::TicketChecked_Key, $replyArr);

		$Play_Key = strtr(Redis_Const::Play_Key, $replyArr);
		$PlayMember_Key = strtr(Redis_Const::PlayMember_Key, $replyArr);
		$LandlordCard_Key = strtr(Redis_Const::LandlordCard_Key, $replyArr);
		$CurrentCard_Key = strtr(Redis_Const::CurrentCard_Key, $replyArr);
		$Chip_Key = strtr(Redis_Const::Chip_Key, $replyArr);
		
		//删除每轮游戏参数
		$Redis_Model->deleteKey($RoomSequence_Key);
		$Redis_Model->deleteKey($RoomScore_Key);
		$Redis_Model->deleteKey($AccountStatus_Key);
		$Redis_Model->deleteKey($TicketChecked_Key);
		//删除每局游戏参数
		$Redis_Model->deleteKey($Play_Key);
		$Redis_Model->deleteKey($PlayMember_Key);
		$Redis_Model->deleteKey($LandlordCard_Key);
		$Redis_Model->deleteKey($CurrentCard_Key);
		$Redis_Model->deleteKey($Chip_Key);
		for ($i=1; $i <= 3; $i++) { 
			$PlayerCard_Key	= "PlayerCard:".$i.":".$room_id;
			$Redis_Model->deleteKey($PlayerCard_Key);
		}

		if(Config::Room_IsReuse == 1){	//可以重复利用房间
			$Room_mkv[Redis_Const::Room_Field_GameNum] = 0;			//游戏局数
			$Room_mkv[Redis_Const::Room_Field_Scoreboard] = "";		//积分榜清零
			$Room_mkv[Redis_Const::Room_Field_Creator] = -1;		//创建者清空
			$Room_mkv[Redis_Const::Room_Field_Status] = Game::RoomStatus_Closed;	//房间状态，1等待、2进行中、3未激活
			$Room_mkv[Redis_Const::Room_Field_StartTime] = -1;
			$mset_result = $Redis_Model->hmsetField($Room_Key,$Room_mkv);
		} else {  //玩一轮即销毁
			$MMYSQL = $this->initMysql();
			$MMYSQL->update(Room)->set('is_close', '1')->where('room_id='.$room_id)->query();

            $RedisLog_Model = Redis_Model::getModelObjectLogs();
            $RedisLog_Model->hdelFiled(Redis_CONST::Room_New_Key,$newRoomNumber);

			$Redis_Model->deleteKey($Room_Key);
		}
		$this->writeLog("[$room_id] 房间清理完毕");
	}

	//整理规则内容文本
	protected function formatRuleText($room_id,$room_data="")
	{
		$rule_text = "";
		$setting = $this->queryRoomSetting($room_id);
		$ticket_count=isset($setting[Redis_Const::Room_Field_TicketCount]) ?$setting[Redis_Const::Room_Field_TicketCount]:1;
		$base_score=isset($setting[Redis_Const::Room_Field_BaseScore]) ?$setting[Redis_Const::Room_Field_BaseScore]: Game::Default_Score;
		$ask_mode=isset($setting[Redis_Const::Room_Field_AskMode]) ?$setting[Redis_Const::Room_Field_AskMode]:2;

		//局数房卡规则
		$ticket_type_text = (Config::GameNum_EachRound * $ticket_count)."局/".$ticket_count."张房卡";
		$rule_text .= $ticket_type_text;

		//筹码类型
		$rule_text .= ",";
		$rule_text .= "底分:".$base_score."分";
			
		//底分
		$rule_text .= ",";
		switch($ask_mode)
		{
			case 1:
				$rule_text .= "规则:轮流问地主";
				break;
			case 2:
				$rule_text .= "规则:随机问地主";
				break;
		}
		return $rule_text;
	}

	protected function saveAccountGameScore($game_info)
	{
		if(Config::Is_SendGameScore == 0){
			return ;
		}
		$game_type = $game_info['game_type'];
		$dealer_num = $game_info['dealer_num'];

		$game_result['time'] = time();
		$game_result['rid'] = $game_info['room_id'];
		$game_result['rnd'] = $game_info['round'];
		$game_result['board'] = $game_info['score_board'];
		
		$game_result_str = json_encode($game_result);
		$push_array = array($game_result_str);

		//连接日志系统
		$Redis_Model = Redis_Model::getModelObjectLogs();
		$replyArr = array("[dealernum]"=>$dealer_num,"[gametype]"=>$game_type);

		$GameScore_Key = strtr(Redis_Const::GameScore_Key, $replyArr);
		$push_result = $Redis_Model->pushListLogs($is_rpush=0,$is_pushx=0,$GameScore_Key,$push_array); //lpush


		//推送到结果处理器
		$msg_array = array(
				'operation' => "PullGameScore",
				'dealer_num'   => $dealer_num,
				'game_type'   => $game_type,
				'data' => array(
					)
				);
		$this->sendToGameResultProcessor($msg_array);

		return true;
	}

    protected function saveAccountGameScore2($game_info)
    {
        $timestamp = time();
        $MMYSQL = $this->initMysql();

        $game_type = $game_info['game_type'];
        $room_id = $game_info['room_id'];
        $round = $game_info['round'];
        $board_array = $game_info['score_board'];
        //保存用户积分
        foreach($board_array as $player_id => $score)
        {
            //保存用户当前数据
            $array['create_time'] = $timestamp;
            $array['game_time'] = $timestamp;
            $array['game_type'] = $game_type;
            $array['room_id'] = $room_id;
            $array['round'] = $round;
            $array['account_id'] = $player_id;
            $array['score'] = $score;
            $MMYSQL->insertReturnID(Room_GameScore,$array);
        }
    }

	/*
		推推送给游戏结果处理器
	*/
	public function sendToGameResultProcessor($msg_array="")
	{
		$message = $this->_JSON($msg_array);

		$socket_name = "Processor";
		$Socket_Model = Socket_Model::getModelObject($socket_name);
		$Socket_Model->sendMessageToSocket($socket_name,$message);

		return true;
	}


	//发牌 全随机规则
	protected function dealCard(){
		$player_cards = array();
		$Card = array(	0x0E,0x0F,
						0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,
						0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,
						0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,
						0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D
					);
        mt_srand();
		$indexs = array_rand($Card, 3);
		shuffle($indexs);
		$num = 0;
		for ($i=0; $i < $player_count; $i++) { 
			$player_cards[] = $Card[$indexs[$num]].','. $Card[$indexs[$num+1]] .','.$Card[$indexs[$num+2]];
			$num += 3;
		}
		return $player_cards;
	}

	/*
		推给定时器服务器
	*/
	public function sendToTimerServer($msg_array = "")
	{
		$message = $this->_JSON($msg_array);

		$socket_name = "Timer";
		$Socket_Model = Socket_Model::getModelObject($socket_name);
		$Socket_Model->sendMessageToSocket($socket_name,$message);

		return true;
	}


	/*
		数组转JSON格式
	*/
	protected function _JSON($array) 
	{  
		$this->__arrayRecursive($array, 'urlencode', true);  
		$json = json_encode($array);  
		return urldecode($json);  
	}
	private function __arrayRecursive(&$array, $function, $apply_to_keys_also = false)  
	{  
		static $recursive_counter = 0;  
		if (++$recursive_counter > 1000) {  
			die('possible deep recursion attack');  
		}  
		foreach ($array as $key => $value) {  
			if (is_array($value)) {  
				$this->__arrayRecursive($array[$key], $function, $apply_to_keys_also);  
			}
			else if(is_object($value))
			{
				$array[$key] = $value;
			} 
			else 
			{  
				$array[$key] = $function($value);  
			}  
	   
			if ($apply_to_keys_also && is_string($key)) {  
				$new_key = $function($key);  
				if ($new_key != $key) {  
					$array[$new_key] = $array[$key];  
					unset($array[$key]);  
				}  
			}  
		}  
		$recursive_counter--;
	}   
	
	/**
    * 拆解接收的json字符串
    * @param string $splitJsonString json字符串
    */
	protected function _splitJsonString($jsonString)
	{
		if(empty($jsonString))
		{
			return OPT_CONST::JSON_FALSE;
		}
		//判断是否为JSON格式
		if(is_null(json_decode($jsonString)))
		{
			//不是json格式
			return OPT_CONST::JSON_FALSE;
		}
		else
		{
			//分拆JSON字符串
			return json_decode($jsonString,true);
		}
	}
	
	
	/*
		返回缺参结果
	*/
	protected function _missingPrameterArr($operation,$prameter)
	{
		return array('result'=>OPT_CONST::MISSING_PARAMETER,'operation'=>$operation,'data'=>array("missing_parameter"=>$prameter),'result_message'=>"缺少参数");
	}
	
	
	
	/*
		判断数据格式是否正确
	*/
	protected function _checkRequestFormat($requestAry)
	{
		if(!isset($requestAry['msgType']))
		{
			$this->logMessage('error', "function(checkRequestFormat):lack of msgType"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>"",'data'=>array("missing_parameter"=>"msgType"),'result_message'=>"缺少参数");
		}
		if(!isset($requestAry['content']))
		{
			$this->logMessage('error', "function(checkRequestFormat):lack of content"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>"",'data'=>array("missing_parameter"=>"content"),'result_message'=>"缺少参数");
		}
		
		return OPT_CONST::POSTARRAY_TRUE;
	}
	
	
	/*
		判断数据格式是否正确
	*/
	protected function _checkPostArray($postArr)
	{
		
		if(!isset($postArr['operation']))
		{
			$this->logMessage('error', "function(checkPostArray):lack of operation"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>"",'data'=>array("missing_parameter"=>""),'result_message'=>"缺少参数");
		}
		else $operation = $postArr['operation'];
		if(!isset($postArr['data']))
		{
			$this->logMessage('error', "function(checkPostArray):lack of data"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>$operation,'data'=>array("missing_parameter"=>""),'result_message'=>"缺少参数");
		}
		if(!isset($postArr['account_id']))
		{
			$this->logMessage('error', "function(checkPostArray):lack of account_id"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>$operation,'data'=>array("missing_parameter"=>""),'result_message'=>"缺少参数");
		}
		if(!isset($postArr['session']))
		{
			$this->logMessage('error', "function(checkPostArray):lack of session"." in file".__FILE__." on Line ".__LINE__);
			return array('result'=>-20,'operation'=>$operation,'data'=>array("missing_parameter"=>""),'result_message'=>"缺少参数");
		}
		return OPT_CONST::POSTARRAY_TRUE;
	}
	
	
	
	/*
		生成微秒
	*/
	protected function getMicroTimestamp()
	{
		$mtime=explode(' ',microtime());
		$mTimestamp=$mtime[1] . substr($mtime[0],2,3);
		
		return $mTimestamp;
	}

	/*
		判断请求链接合法性
	*/
	protected function checkRequestClientLegal($client_id,$room_id,$account_id)
	{
		return true;
		//绑定用户UID
		$replyArr = array("[roomid]"=>$room_id,"[accountid]"=>$account_id);
		$room_aid = strtr(Game::RoomUser_UID, $replyArr);

		$client_array = Gateway::getClientIdByUid($room_aid);
		if(is_array($client_array) && count($client_array) > 0)
		{
			foreach($client_array as $bind_client)
			{
				if($bind_client == $client_id)
				{
					return true;
				}
			}
		}
		return false;
	}
	
	
	
}
?>